// models/SysMenu.js
const mongoose = require("mongoose");
const { Schema } = mongoose;

/**
 * 系统菜单表 - 对应 MySQL sys_menu 表
 * 使用树形结构存储菜单层级关系
 */
const sysMenuSchema = new Schema(
  {
    // 菜单ID - 对应MySQL的menu_id
    menuId: {
      type: Number,
      required: true,
      unique: true,
      index: true,
      comment: "菜单ID",
    },

    // 菜单名称 - 对应MySQL的menu_name
    menuName: {
      type: String,
      required: [true, "菜单名称不能为空"],
      trim: true,
      minlength: [1, "菜单名称至少1个字符"],
      maxlength: [50, "菜单名称不能超过50个字符"],
      comment: "菜单名称",
    },

    // 父菜单ID - 对应MySQL的parent_id
    parentId: {
      type: Number,
      default: 0,
      index: true,
      comment: "父菜单ID",
    },

    // 显示顺序 - 对应MySQL的order_num
    orderNum: {
      type: Number,
      default: 0,
      min: [0, "显示顺序不能小于0"],
      comment: "显示顺序",
    },

    // 路由地址 - 对应MySQL的path
    path: {
      type: String,
      default: "",
      maxlength: [200, "路由地址不能超过200个字符"],
      comment: "路由地址",
    },

    // 组件路径 - 对应MySQL的component
    component: {
      type: String,
      default: null,
      maxlength: [255, "组件路径不能超过255个字符"],
      comment: "组件路径",
    },

    // 是否为外链 - 对应MySQL的is_frame
    isFrame: {
      type: Boolean,
      default: false,
      comment: "是否为外链（0是 1否）",
    },

    // 是否缓存 - 对应MySQL的is_cache
    isCache: {
      type: Boolean,
      default: false,
      comment: "是否缓存（0缓存 1不缓存）",
    },

    // 菜单类型 - 对应MySQL的menu_type
    menuType: {
      type: String,
      enum: {
        values: ["M", "C", "F"],
        message: "菜单类型必须是 M(目录)、C(菜单) 或 F(按钮)",
      },
      default: "",
      comment: "菜单类型（M目录 C菜单 F按钮）",
    },

    // 显示状态 - 对应MySQL的visible
    visible: {
      type: String,
      enum: {
        values: ["0", "1"],
        message: "显示状态必须是 0(显示) 或 1(隐藏)",
      },
      default: "0",
      comment: "菜单状态（0显示 1隐藏）",
    },

    // 菜单状态 - 对应MySQL的status
    status: {
      type: String,
      enum: {
        values: ["0", "1"],
        message: "菜单状态必须是 0(正常) 或 1(停用)",
      },
      default: "0",
      comment: "菜单状态（0正常 1停用）",
    },

    // 权限标识 - 对应MySQL的perms
    perms: {
      type: String,
      default: null,
      maxlength: [100, "权限标识不能超过100个字符"],
      comment: "权限标识",
    },

    // 菜单图标 - 对应MySQL的icon
    icon: {
      type: String,
      default: "#",
      maxlength: [100, "菜单图标不能超过100个字符"],
      comment: "菜单图标",
    },

    // 创建者 - 对应MySQL的create_by
    createBy: {
      type: String,
      default: "",
      comment: "创建者",
    },

    // 创建时间 - 对应MySQL的create_time
    createTime: {
      type: Date,
      default: Date.now,
      comment: "创建时间",
    },

    // 更新者 - 对应MySQL的update_by
    updateBy: {
      type: String,
      default: "",
      comment: "更新者",
    },

    // 更新时间 - 对应MySQL的update_time
    updateTime: {
      type: Date,
      default: Date.now,
      comment: "更新时间",
    },

    // 备注 - 对应MySQL的remark
    remark: {
      type: String,
      default: "",
      maxlength: [500, "备注不能超过500个字符"],
      comment: "备注",
    },
  },
  {
    // Schema 选项
    timestamps: false,
    collection: "sys_menus",
    toJSON: { virtuals: true },
    toObject: { virtuals: true },
  }
);

// 创建复合索引
sysMenuSchema.index({ parentId: 1, orderNum: 1 });
sysMenuSchema.index({ menuType: 1, status: 1 });
sysMenuSchema.index({ visible: 1 });
sysMenuSchema.index({ perms: 1 });
sysMenuSchema.index({ createTime: -1 });

// 虚拟字段
sysMenuSchema.virtual("isActive").get(function () {
  return this.status === "0";
});

sysMenuSchema.virtual("isVisible").get(function () {
  return this.visible === "0";
});

sysMenuSchema.virtual("isRoot").get(function () {
  return this.parentId === 0;
});

sysMenuSchema.virtual("menuTypeText").get(function () {
  const menuTypeMap = { M: "目录", C: "菜单", F: "按钮" };
  return menuTypeMap[this.menuType] || "未知";
});

sysMenuSchema.virtual("statusText").get(function () {
  const statusMap = { 0: "正常", 1: "停用" };
  return statusMap[this.status] || "未知";
});

sysMenuSchema.virtual("visibleText").get(function () {
  const visibleMap = { 0: "显示", 1: "隐藏" };
  return visibleMap[this.visible] || "未知";
});

// 子菜单虚拟字段
sysMenuSchema.virtual("children", {
  ref: "SysMenu",
  localField: "menuId",
  foreignField: "parentId",
  justOne: false,
});

// 父菜单虚拟字段
sysMenuSchema.virtual("parent", {
  ref: "SysMenu",
  localField: "parentId",
  foreignField: "menuId",
  justOne: true,
});

// 实例方法
sysMenuSchema.methods = {
  // 启用/禁用菜单
  toggleStatus: function () {
    this.status = this.status === "0" ? "1" : "0";
    this.updateTime = new Date();
    return this.save();
  },

  // 显示/隐藏菜单
  toggleVisible: function () {
    this.visible = this.visible === "0" ? "1" : "0";
    this.updateTime = new Date();
    return this.save();
  },

  // 更新菜单信息
  updateMenu: function (updateData) {
    Object.keys(updateData).forEach((key) => {
      if (key !== "menuId" && this.schema.paths[key]) {
        this[key] = updateData[key];
      }
    });
    this.updateTime = new Date();
    return this.save();
  },

  // 获取菜单基本信息（用于展示）
  toBasicJSON: function () {
    return {
      menuId: this.menuId,
      menuName: this.menuName,
      parentId: this.parentId,
      orderNum: this.orderNum,
      path: this.path,
      component: this.component,
      isFrame: this.isFrame,
      isCache: this.isCache,
      menuType: this.menuType,
      menuTypeText: this.menuTypeText,
      visible: this.visible,
      visibleText: this.visibleText,
      status: this.status,
      statusText: this.statusText,
      perms: this.perms,
      icon: this.icon,
      remark: this.remark,
    };
  },

  // 检查是否是目录
  isDirectory: function () {
    return this.menuType === "M";
  },

  // 检查是否是菜单
  isMenu: function () {
    return this.menuType === "C";
  },

  // 检查是否是按钮
  isButton: function () {
    return this.menuType === "F";
  },

  // 检查是否有权限标识
  hasPerms: function () {
    return !!this.perms && this.perms.trim() !== "";
  },

  // 验证权限标识格式
  validatePerms: function () {
    if (!this.perms) return true;
    const permsRegex = /^[a-zA-Z0-9_:]+$/;
    return permsRegex.test(this.perms);
  },
};

// 静态方法
sysMenuSchema.statics = {
  // 根据菜单ID查找菜单
  findByMenuId: function (menuId) {
    return this.findOne({ menuId: menuId });
  },

  // 根据权限标识查找菜单
  findByPerms: function (perms) {
    return this.findOne({ perms: perms });
  },

  // 根据菜单名称查找菜单
  findByMenuName: function (menuName) {
    return this.findOne({
      menuName: new RegExp(`^${menuName}$`, "i"),
    });
  },

  // 获取根菜单（parentId = 0）
  findRootMenus: function () {
    return this.find({
      parentId: 0,
      status: "0",
    }).sort({ orderNum: 1 });
  },

  // 获取所有有效菜单（树形结构）
  findMenuTree: async function (options = {}) {
    const {
      includeHidden = false,
      includeDisabled = false,
      menuTypes = ["M", "C", "F"],
    } = options;

    const query = {};

    if (!includeDisabled) {
      query.status = "0";
    }

    if (!includeHidden) {
      query.visible = "0";
    }

    if (menuTypes && menuTypes.length > 0) {
      query.menuType = { $in: menuTypes };
    }

    const menus = await this.find(query).sort({ parentId: 1, orderNum: 1 });

    return this.buildMenuTree(menus);
  },

  // 构建菜单树形结构
  buildMenuTree: function (menus, parentId = 0) {
    const tree = [];

    for (const menu of menus) {
      if (menu.parentId === parentId) {
        const children = this.buildMenuTree(menus, menu.menuId);
        if (children.length > 0) {
          menu._doc.children = children;
        }
        tree.push(menu);
      }
    }

    return tree;
  },

  // 根据父菜单ID获取子菜单
  findChildrenByParentId: function (parentId, options = {}) {
    const {
      includeHidden = false,
      includeDisabled = false,
      menuTypes = ["M", "C", "F"],
    } = options;

    const query = {
      parentId: parentId,
    };

    if (!includeDisabled) {
      query.status = "0";
    }

    if (!includeHidden) {
      query.visible = "0";
    }

    if (menuTypes && menuTypes.length > 0) {
      query.menuType = { $in: menuTypes };
    }

    return this.find(query).sort({ orderNum: 1 });
  },

  // 获取所有目录类型的菜单
  findDirectories: function () {
    return this.find({
      menuType: "M",
      status: "0",
    }).sort({ orderNum: 1 });
  },

  // 获取所有菜单类型的菜单（非按钮）
  findMenuItems: function () {
    return this.find({
      menuType: { $in: ["M", "C"] },
      status: "0",
      visible: "0",
    }).sort({ orderNum: 1 });
  },

  // 获取所有按钮类型的菜单
  findButtons: function () {
    return this.find({
      menuType: "F",
      status: "0",
    }).sort({ orderNum: 1 });
  },

  // 根据菜单类型获取菜单
  findByMenuType: function (menuType) {
    return this.find({
      menuType: menuType,
      status: "0",
    }).sort({ orderNum: 1 });
  },

  // 分页查询菜单
  findMenusPaginated: function (options = {}) {
    const {
      page = 1,
      limit = 10,
      menuName = "",
      menuType = "",
      status = "",
      visible = "",
    } = options;

    const skip = (page - 1) * limit;
    const query = {};

    // 构建查询条件
    if (menuName) {
      query.menuName = { $regex: menuName, $options: "i" };
    }

    if (menuType) {
      query.menuType = menuType;
    }

    if (status) {
      query.status = status;
    }

    if (visible) {
      query.visible = visible;
    }

    return Promise.all([
      this.find(query)
        .skip(skip)
        .limit(limit)
        .sort({ parentId: 1, orderNum: 1 }),
      this.countDocuments(query),
    ]).then(([menus, total]) => ({
      menus,
      pagination: {
        page: parseInt(page),
        limit: parseInt(limit),
        total,
        pages: Math.ceil(total / limit),
      },
    }));
  },

  // 菜单统计
  getMenuStats: function () {
    return this.aggregate([
      {
        $group: {
          _id: "$menuType",
          count: { $sum: 1 },
          activeCount: {
            $sum: { $cond: [{ $eq: ["$status", "0"] }, 1, 0] },
          },
          visibleCount: {
            $sum: { $cond: [{ $eq: ["$visible", "0"] }, 1, 0] },
          },
          avgOrderNum: { $avg: "$orderNum" },
        },
      },
      {
        $project: {
          menuType: "$_id",
          count: 1,
          activeCount: 1,
          visibleCount: 1,
          avgOrderNum: { $round: ["$avgOrderNum", 2] },
          _id: 0,
        },
      },
      {
        $sort: { menuType: 1 },
      },
    ]);
  },

  // 检查菜单名称是否已存在（同父级下）
  isMenuNameExists: function (menuName, parentId, excludeMenuId = null) {
    const query = {
      menuName: new RegExp(`^${menuName}$`, "i"),
      parentId: parentId,
    };

    if (excludeMenuId) {
      query.menuId = { $ne: excludeMenuId };
    }

    return this.findOne(query);
  },

  // 检查权限标识是否已存在
  isPermsExists: function (perms, excludeMenuId = null) {
    if (!perms) return Promise.resolve(null);

    const query = {
      perms: perms,
    };

    if (excludeMenuId) {
      query.menuId = { $ne: excludeMenuId };
    }

    return this.findOne(query);
  },

  // 获取最大显示顺序
  getMaxOrderNum: function (parentId = null) {
    const query = {};
    if (parentId !== null) {
      query.parentId = parentId;
    }

    return this.findOne(query)
      .sort({ orderNum: -1 })
      .select("orderNum")
      .then((menu) => (menu ? menu.orderNum : 0));
  },

  // 获取下一个可用的菜单ID
  getNextMenuId: async function () {
    const lastMenu = await this.findOne().sort({ menuId: -1 }).select("menuId");

    return lastMenu ? lastMenu.menuId + 1 : 2000; // 从2000开始
  },

  // 根据菜单ID列表获取菜单信息
  findMenusByIds: function (menuIds) {
    return this.find({
      menuId: { $in: menuIds },
    }).sort({ orderNum: 1 });
  },

  // 搜索菜单（名称或权限标识）
  searchMenus: function (keyword, options = {}) {
    const {
      page = 1,
      limit = 10,
      menuType = "",
      status = "",
      visible = "",
    } = options;

    const skip = (page - 1) * limit;
    const query = {
      $or: [
        { menuName: { $regex: keyword, $options: "i" } },
        { perms: { $regex: keyword, $options: "i" } },
        { path: { $regex: keyword, $options: "i" } },
      ],
    };

    // 菜单类型筛选
    if (menuType) {
      query.menuType = menuType;
    }

    // 状态筛选
    if (status) {
      query.status = status;
    }

    // 显示状态筛选
    if (visible) {
      query.visible = visible;
    }

    return Promise.all([
      this.find(query)
        .skip(skip)
        .limit(limit)
        .sort({ parentId: 1, orderNum: 1 }),
      this.countDocuments(query),
    ]).then(([menus, total]) => ({
      menus,
      pagination: {
        page: parseInt(page),
        limit: parseInt(limit),
        total,
        pages: Math.ceil(total / limit),
      },
    }));
  },

  // 获取用户有权限的菜单树
  findUserMenuTree: async function (perms = []) {
    let query = {
      status: "0",
      visible: "0",
      menuType: { $in: ["M", "C"] }, // 只返回目录和菜单，不包含按钮
    };

    // 如果有权限列表，添加权限过滤
    if (perms && perms.length > 0) {
      query.$or = [
        { perms: { $in: perms } },
        { perms: { $exists: false } },
        { perms: "" },
        { perms: null },
      ];
    }

    const menus = await this.find(query).sort({ parentId: 1, orderNum: 1 });

    return this.buildMenuTree(menus);
  },
};

// 查询助手
sysMenuSchema.query = {
  // 按菜单类型筛选
  byMenuType: function (menuType) {
    return this.where("menuType").equals(menuType);
  },

  // 按状态筛选
  byStatus: function (status) {
    return this.where("status").equals(status);
  },

  // 按显示状态筛选
  byVisible: function (visible) {
    return this.where("visible").equals(visible);
  },

  // 按父菜单ID筛选
  byParentId: function (parentId) {
    return this.where("parentId").equals(parentId);
  },

  // 按显示顺序排序
  sortByOrder: function (direction = "asc") {
    const sortOrder = direction === "desc" ? -1 : 1;
    return this.sort({ orderNum: sortOrder });
  },

  // 搜索菜单名称或权限标识
  searchByKeyword: function (keyword) {
    return this.where({
      $or: [
        { menuName: { $regex: keyword, $options: "i" } },
        { perms: { $regex: keyword, $options: "i" } },
      ],
    });
  },

  // 只查询有效的菜单（启用且显示）
  onlyActive: function () {
    return this.where({
      status: "0",
      visible: "0",
    });
  },
};

// 中间件
sysMenuSchema.pre("save", function (next) {
  // 更新更新时间
  this.updateTime = new Date();

  // 验证权限标识格式
  if (this.isModified("perms") && this.perms && !this.validatePerms()) {
    return next(
      new Error("权限标识格式不正确，只能包含字母、数字、冒号和下划线")
    );
  }

  // 如果是按钮类型，必须要有权限标识
  if (this.menuType === "F" && (!this.perms || this.perms.trim() === "")) {
    return next(new Error("按钮类型的菜单必须设置权限标识"));
  }

  // 如果是外链，path必须以http://或https://开头
  if (
    this.isFrame &&
    this.path &&
    !this.path.startsWith("http://") &&
    !this.path.startsWith("https://")
  ) {
    return next(new Error("外链菜单的路由地址必须以http://或https://开头"));
  }

  next();
});

// 创建模型
const SysMenu = mongoose.model("SysMenu", sysMenuSchema);

module.exports = SysMenu;
